// Package sys
// @Link  https://github.com/bufanyun/hotgo
// @Copyright  Copyright (c) 2025 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
// @AutoGenerate Version 2.15.11
package sys

import (
	"context"
	"encoding/json"
	"fmt"
	"hotgo/internal/consts"
	"hotgo/internal/dao"
	"hotgo/internal/library/contexts"
	"hotgo/internal/library/hfsm"
	"hotgo/internal/library/hgorm"
	"hotgo/internal/library/hgorm/handler"
	"hotgo/internal/model/entity"
	"hotgo/internal/model/input/adminin"
	"hotgo/internal/model/input/apiin"
	"hotgo/internal/model/input/expressinfoin"
	"hotgo/internal/model/input/form"
	"hotgo/internal/model/input/payin"
	"hotgo/internal/model/input/sysin"
	"hotgo/internal/service"
	"hotgo/utility/convert"
	"hotgo/utility/excel"
	"time"

	"github.com/bwmarrin/snowflake"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/samber/lo"
	"github.com/shopspring/decimal"
)

type sSysUserOrder struct {
	sNode *snowflake.Node
}

func NewSysUserOrder() *sSysUserOrder {
	node, err := snowflake.NewNode(1) // Initialize the snowflake node
	if err != nil {
		g.Log().Fatal(gctx.New(), "Failed to initialize snowflake node:", err)
		return &sSysUserOrder{}
	}
	this := new(sSysUserOrder)
	this.sNode = node
	return this
}

func init() {
	service.RegisterSysUserOrder(NewSysUserOrder())
}

// Model 订单中心ORM模型
func (s *sSysUserOrder) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
	return handler.Model(dao.Order.Ctx(ctx), option...)
}

// List 获取订单中心列表
func (s *sSysUserOrder) List(ctx context.Context, in *sysin.UserOrderListInp) (list []*sysin.UserOrderListModel, totalCount int, err error) {

	list = make([]*sysin.UserOrderListModel, 0)

	// 逻辑删除查询
	deleted := false

	mod := s.Model(ctx)

	// 数据隔离
	loginUser := contexts.GetUser(ctx)
	if !service.AdminMember().VerifySuperId(ctx, loginUser.Id) {
		switch contexts.GetRoleId(ctx) {
		case consts.RoleManage:
		case consts.RoleUser, consts.RoleXiaoke, consts.RoleService: // 用户
			if in.UserID != 0 {
				err = gerror.New("只能查看自己的订单")
				return
			}
			in.UserID = loginUser.Id
			deleted = true
		case consts.RoleStore:
			user := contexts.GetUser(ctx)
			if in.StoreId == 0 {
				return nil, 0, gerror.NewCode(gcode.CodeMissingParameter, "门店ID不能为空")
			}
			// 数据权限验证
			{
				var storeMember entity.StoreMember
				if err = dao.StoreMember.Ctx(ctx).Where(dao.StoreMember.Columns().StoreId, in.StoreId).Where(dao.StoreMember.Columns().MemberId, user.Id).Scan(&storeMember); err != nil {
					return nil, 0, gerror.NewCode(gcode.CodeInvalidRequest, "无权限")
				}
			}
			// 查询订单类型
			if in.OrderStatus == "" {
				mod = mod.WhereIn(dao.Order.Columns().Status, []string{
					consts.UserOrderStatusWaitVerify,
					consts.UserOrderStatusDone,
				})
			}
		default:
			return nil, 0, gerror.NewCode(gcode.CodeInvalidRequest, "无权限")
		}
	}

	// 字段过滤
	mod = mod.FieldsPrefix(dao.Order.Table(), sysin.UserOrderListModel{})
	mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderListModel{}, &dao.Product, "product"))
	//mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderListModel{}, &dao.Store, "store"))
	mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderListModel{}, &dao.AdminMember, "adminMember"))
	mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderListModel{}, &dao.MemberCard, "memberCard"))
	mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderListModel{}, &dao.ExpressInfo, "expressInfo"))

	mod = mod.LeftJoinOnFields(dao.Product.Table(), dao.Order.Columns().ProductId, "=", dao.Product.Columns().Id)
	//mod = mod.LeftJoinOnFields(dao.Store.Table(), dao.Order.Columns().StoreId, "=", dao.Store.Columns().Id)
	mod = mod.LeftJoinOnFields(dao.AdminMember.Table(), dao.Order.Columns().UserId, "=", dao.AdminMember.Columns().Id)
	mod = mod.LeftJoinOnFields(dao.MemberCard.Table(), dao.Order.Columns().MemberCardId, "=", dao.MemberCard.Columns().Id)
	mod = mod.LeftJoinOnFields(dao.ExpressInfo.Table(), dao.Order.Columns().ExpressInfoId, "=", dao.ExpressInfo.Columns().Id)

	// 查询订单UUID
	if in.Uid != "" {
		mod = mod.WhereLike(dao.Order.Columns().Uid, "%"+in.Uid+"%")
	}

	// 查询交易ID
	if in.TraceId != "" {
		mod = mod.WhereLike(dao.Order.Columns().TraceId, "%"+in.TraceId+"%")
	}

	// 查询订单状态
	if in.StatusNum != 0 {
		in.Status = consts.GetOrderStatusByProductScene(in.StatusNum)
	}
	if in.Status != "" {
		mod = mod.WhereIn(dao.Order.Columns().Status, in.Status)
	}

	// 查询商家ID
	if in.StoreId > 0 {
		mod = mod.Where(dao.Order.Columns().StoreId, in.StoreId)
	}

	// 查询订单类型
	if in.OrderType != "" {
		mod = mod.WhereIn(dao.Order.Columns().OrderType, in.OrderType)
	}

	// 查询订单状态
	if in.OrderStatus != "" {
		mod = mod.Where(dao.Order.Columns().Status, in.OrderStatus)
	}

	// 查询商品ID
	if in.ProductId > 0 {
		mod = mod.Where(dao.Order.Columns().ProductId, in.ProductId)
	}

	// 查询创建时间
	if len(in.CreatedAt) == 2 {
		mod = mod.WhereBetween(dao.Order.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
	}

	// 查询归档时间
	if len(in.ArchiveTime) == 2 {
		mod = mod.WhereBetween(dao.Order.Columns().ArchiveTime, in.ArchiveTime[0], in.ArchiveTime[1])
	}

	// 查询手机号码
	if in.AdminMemberMobile != "" {
		mod = mod.WherePrefixLike(dao.AdminMember.Table(), dao.AdminMember.Columns().Mobile, "%"+in.AdminMemberMobile+"%")
	}

	// 用户id
	if in.UserID > 0 {
		mod = mod.Where(dao.Order.Columns().UserId, in.UserID)
	}

	// 逻辑删除查询
	if deleted {
		mod = mod.Where("deleted", 0)
	}

	// 分页
	mod = mod.Page(in.Page, in.PerPage)

	// 排序
	mod = mod.OrderDesc(dao.Order.Table() + "." + dao.Order.Columns().Id)

	// 查询数据
	if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
		err = gerror.Wrap(err, "获取订单中心列表失败，请稍后重试！")
		return
	}

	// 设置代付款结束时间
	for _, v := range list {
		if v.Status == consts.UserOrderStatusNot {
			v.PayTime = v.CreatedAt.Add(15 * time.Minute)
		}
		if v.OrderType == consts.OrderTypeMemberOrder && v.MemberCardId != 0 {
			v.ProductName = v.MemberCardName
			v.ProductMainImage = gjson.New([]string{v.MemberCardImgUrl})
			v.MemberCardName = ""
			v.MemberCardImgUrl = ""
		}
	}
	return
}

// Export 导出订单中心
func (s *sSysUserOrder) Export(ctx context.Context, in *sysin.UserOrderListInp) (err error) {
	list, totalCount, err := s.List(ctx, in)
	if err != nil {
		return
	}

	// 字段的排序是依据tags的字段顺序，如果你不想使用默认的排序方式，可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
	tags, err := convert.GetEntityDescTags(sysin.UserOrderExportModel{})
	if err != nil {
		return
	}

	var (
		fileName  = "导出订单中心-" + gctx.CtxId(ctx)
		sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, form.CalPageCount(totalCount, in.PerPage), in.Page, len(list))
		exports   []sysin.UserOrderExportModel
	)

	if err = gconv.Scan(list, &exports); err != nil {
		return
	}

	err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
	return
}

// Edit 修改/新增订单中心
func (s *sSysUserOrder) Edit(ctx context.Context, in *sysin.UserOrderEditInp) (id int64, err error) {

	err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {

		// 修改
		if in.Id > 0 {
			id = in.Id
			if _, err = s.Model(ctx).
				Fields(sysin.UserOrderUpdateFields{}).
				WherePri(in.Id).Data(in).OmitEmptyData().Update(); err != nil {
				err = gerror.Wrap(err, "修改订单中心失败，请稍后重试！")
			}
			return
		}

		// 新增
		var uid string
		switch in.OrderType {
		case consts.OrderTypePointRight:
			uid = "PR-"
		case consts.OrderTypePointECommerce:
			uid = "PE-"
		case consts.OrderTypeGroupOrder:
			uid = "GO-"
		case consts.OrderTypeMemberOrder:
			uid = "MV-"
		}
		in.Uid = uid + s.sNode.Generate().String()
		in.Status = consts.UserOrderStatusNot
		if in.UseAmount == 0 && in.UsePoints > 0 {
			in.PayMethod = consts.PayTypePoint
		}

		// 获取商品门店商户
		if in.ProductId != 0 {
			res, err2 := service.Product().GetStoreInfo(ctx, &apiin.GetStoreInfoInp{
				Id: in.ProductId,
			})
			if err2 != nil {
				err = err2
				return
			}
			if res.BusinessId == 0 {
				in.StoreId = res.StoreId
			} else {
				in.BusinessId = res.BusinessId
			}
		}

		id, err = s.Model(ctx, &handler.Option{FilterAuth: false}).
			Fields(sysin.UserOrderInsertFields{}).
			Data(in).InsertAndGetId()
		if err != nil {
			err = gerror.Wrap(err, "新增订单中心失败，请稍后重试！")
			return
		}
		hfsm.OFSM.NewOrderFSM(consts.UserOrderStatusNot, id)
		return
	})
	return
}

// CreateFinishOrderHistory 创建订单历史记录(用于一些赠送的活动，创建一个订单记录，但不操作钱和积分，状态直接是已完成)
func (s *sSysUserOrder) CreateFinishOrderHistory(ctx context.Context, in *sysin.UserOrderEditInp) (id int64, err error) {
	// 创建订单历史记录
	var uid string
	switch in.OrderType {
	case consts.OrderTypePointRight:
		uid = "PR-"
	case consts.OrderTypePointECommerce:
		uid = "PE-"
	case consts.OrderTypeGroupOrder:
		uid = "GO-"
	case consts.OrderTypeMemberOrder:
		uid = "MV-"
	}
	in.Uid = uid + s.sNode.Generate().String()
	in.Status = consts.UserOrderStatusNot
	//if in.UseAmount == 0 && in.UsePoints > 0 {
	// 默认为系统赠送
	if in.PayMethod == "" {
		in.PayMethod = consts.PayTypeGift
	}
	//}
	in.Status = consts.UserOrderStatusDone

	id, err = s.Model(ctx, &handler.Option{FilterAuth: false}).
		Fields(sysin.UserOrderInsertFields{}).
		Data(in).InsertAndGetId()
	if err != nil {
		err = gerror.Wrap(err, "新增订单中心失败，请稍后重试！")
		return
	}
	return
}

// Update 修改订单
func (s *sSysUserOrder) Update(ctx context.Context, in *sysin.UserOrderEditInp) (id int64, err error) {
	err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
		// 修改
		if _, err = s.Model(ctx).
			Fields("deleted").
			WherePri(in.Id).Data(in).Update(); err != nil {
			err = gerror.Wrap(err, "修改订单失败，请稍后重试！")
		}
		return
	})
	return
}

// Delete 删除订单中心
func (s *sSysUserOrder) Delete(ctx context.Context, in *sysin.UserOrderDeleteInp) (err error) {

	if _, err = s.Model(ctx).WherePri(in.Id).Unscoped().Delete(); err != nil {
		err = gerror.Wrap(err, "删除订单中心失败，请稍后重试！")
		return
	}
	return
}

// View 获取订单中心指定信息
func (s *sSysUserOrder) View(ctx context.Context, in *sysin.UserOrderViewInp) (res *sysin.UserOrderViewModel, err error) {
	mod := s.Model(ctx)
	mod = mod.FieldsPrefix(dao.Order.Table(), sysin.UserOrderViewModel{})
	mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderViewModel{}, &dao.AdminMember, "adminMember"))
	mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderViewModel{}, &dao.Product, "product"))
	//mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderViewModel{}, &dao.Store, "store"))
	mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderViewModel{}, &dao.ExpressInfo, "expressInfo"))

	// 关联表字段
	mod = mod.LeftJoinOnFields(dao.AdminMember.Table(), dao.Order.Columns().UserId, "=", dao.AdminMember.Columns().Id)
	mod = mod.LeftJoinOnFields(dao.Product.Table(), dao.Order.Columns().ProductId, "=", dao.Product.Columns().Id)
	//mod = mod.LeftJoinOnFields(dao.Store.Table(), dao.Order.Columns().StoreId, "=", dao.Store.Columns().Id)
	mod = mod.LeftJoinOnFields(dao.ExpressInfo.Table(), dao.Order.Columns().ExpressInfoId, "=", dao.ExpressInfo.Columns().Id)
	if err = mod.WherePri(in.Id).Scan(&res); err != nil {
		err = gerror.Wrap(err, "获取订单中心信息，请稍后重试！")
		return
	}
	return
}

// Status 更新订单中心状态
func (s *sSysUserOrder) Status(ctx context.Context, in *sysin.UserOrderStatusInp) (err error) {
	if _, err = s.Model(ctx).WherePri(in.Id).Data(g.Map{
		dao.Order.Columns().Status: in.Status,
	}).Update(); err != nil {
		err = gerror.Wrap(err, "更新订单中心状态失败，请稍后重试！")
		return
	}
	return
}

// VerifiedCount 增加订单中心已核销数
func (s *sSysUserOrder) VerifiedCount(ctx context.Context, in *sysin.UserOrderVerifiedCountInp) (err error) {
	if _, err = s.Model(ctx).WherePri(in.Id).Increment(dao.Order.Columns().VerifiedCount, in.VerifiedCount); err != nil {
		err = gerror.Wrap(err, "更新订单中心状态失败，请稍后重试！")
		return
	}
	return
}

// GetOrderByUID 根据订单uid获取订单信息
func (this *sSysUserOrder) GetOrderByUID(ctx context.Context, uid string, userId int64) (res *sysin.UserOrderViewModel, err error) {
	mod := this.Model(ctx)
	mod = mod.FieldsPrefix(dao.Order.Table(), sysin.UserOrderViewModel{})
	mod = mod.Fields(hgorm.JoinFields(ctx, sysin.UserOrderViewModel{}, &dao.Product, "product"))

	// 关联表字段
	mod = mod.LeftJoinOnFields(dao.Product.Table(), dao.Order.Columns().ProductId, "=", dao.Product.Columns().Id)

	mod = mod.Where(dao.Order.Columns().Uid, uid)
	if userId > 0 {
		mod = mod.Where(dao.Order.Columns().UserId, userId)
	}
	err = mod.Scan(&res)
	if err != nil {
		err = gerror.Wrap(err, "获取订单中心信息，请稍后重试！")
		return
	}
	return
}

// ToExpressed 订单状态转为已发货
func (this *sSysUserOrder) ToExpressed(ctx context.Context, in *sysin.UserOrderStatus2ExpressedInp) (res *sysin.UserOrderStatus2ExpressedModel, err error) {
	var orderInfo *sysin.UserOrderViewModel
	orderInfo, err = this.GetOrderByUID(ctx, in.OrderUID, 0)
	if err != nil {
		err = gerror.Wrap(err, "获取订单中心信息，请稍后重试！")
		return
	}
	userInfo := contexts.GetUser(ctx)
	hfsm.OFSM.PushState(orderInfo.Id, consts.WaitExpressToExpressedEvent, in.ExpressCompany, in.ExpressNumber, userInfo.Id)
	return
}

// PayNotify 订单回调业务处理
func (this *sSysUserOrder) PayNotify(ctx context.Context, in *payin.NotifyCallFuncInp) (err error) {
	// 会员订单处理
	//  * 需要优先处理会员订单，团购订单需要加积分
	if in.Pay.OrderMvSn != "" {
		err = this.PayNotifyBusiness(ctx, in.Pay.OrderMvSn, in.Pay.TransactionId)
		if err != nil {
			return
		}
	}

	// 商品订单处理
	if in.Pay.OrderSn != "" {
		err = this.PayNotifyBusiness(ctx, in.Pay.OrderSn, in.Pay.TransactionId)
		if err != nil {
			return
		}
	}
	return
}

// 业务处理方法
func (this *sSysUserOrder) PayNotifyBusiness(ctx context.Context, sn, traceId string) (err error) {
	var models *entity.Order
	if err = this.Model(ctx).Where(dao.Order.Columns().Uid, sn).Scan(&models); err != nil {
		return
	}
	if models == nil {
		err = gerror.New("订单不存在")
		return
	}
	if models.Status != consts.UserOrderStatusNot {
		err = gerror.New("订单已处理，请勿重复操作")
		return
	}

	if _, err = service.SysUserOrder().Model(ctx).Data(g.Map{
		dao.Order.Columns().TraceId: traceId,
	}).WherePri(models.Id).Update(); err != nil {
		return
	}

	// 更新订单状态
	err = hfsm.OFSM.PushState(models.Id, consts.NotToPayEvent)
	if err != nil {
		return
	}
	return
}

func (this *sSysUserOrder) OrderPay(ctx context.Context, in *sysin.OrderPayInp) (res *sysin.OrderPayModel, err error) {

	if in.ProductID == 0 && in.ProductNewID == 0 && in.MemberCardID == 0 {
		err = gerror.New("请选择消费内容")
		return
	}

	//openid, err := service.CommonWechat().GetOpenId(ctx)
	//if err != nil {
	//	glog.Errorf(ctx, "Failed to get openid: %v", err)
	//	err = gerror.Newf("Failed to get openid: %v", err)
	//	return nil, err
	//}
	//userInfo := contexts.GetUser(ctx)
	tx, err := g.DB().Begin(ctx)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	//user, err := service.SysUserModule().GetByOpenID(ctx, openid)
	//user := contexts.GetUser(ctx)
	//if err != nil {
	//	return nil, gerror.New("Failed to get user info")
	//}
	userInfo, err := service.AdminMember().GetById(ctx, &adminin.GetByIdInp{
		Id: contexts.GetUserId(ctx),
	})
	if userInfo == nil || err != nil {
		return nil, gerror.New("用户信息获取失败")
	}

	// 商品订单
	productOrder := &sysin.UserOrderViewModel{}
	// 商品金额
	productAmount := decimal.NewFromFloat(0)
	// 商品积分
	productPoint := decimal.NewFromFloat(0)
	// 商品成本价
	productCost := decimal.NewFromFloat(0)
	// 会员订单
	memberOrder := &sysin.UserOrderViewModel{}
	// 会员金额
	memberAmount := decimal.NewFromFloat(0)

	// 分享用户 id
	productOrder.ShareMemberId = in.ShareMemberId

	// 订单标题
	subject := ""

	// 商品
	if in.ProductID != 0 || in.ProductNewID != 0 {
		// 获取新人商品信息
		var productNew *sysin.ProductNewViewModel
		if in.ProductNewID != 0 {
			productNew, err = service.SysProductNew().View(ctx, &sysin.ProductNewViewInp{
				Id: in.ProductNewID,
			})
			if err != nil {
				glog.Errorf(ctx, "Failed to retrieve product_new: %v", err)
				return nil, err
			}
			in.ProductID = productNew.ProductId
		}

		// 获取商品信息
		product, err := service.SysProduct().View(ctx, &sysin.ProductViewInp{
			Id: in.ProductID,
		})
		if err != nil {
			glog.Errorf(ctx, "Failed to retrieve product: %v", err)
			return nil, err
		}
		if product == nil {
			return nil, gerror.New("商品不存在")
		}

		subject = product.Name

		// 如果是新人商品，修改积分价格
		if in.ProductNewID != 0 && productNew != nil {
			product.Integral = productNew.NewPrice
		}

		// 计算价格
		productAmount = decimal.NewFromFloat(product.SalePrice).Mul(decimal.NewFromInt(int64(in.Qty))).Add(decimal.NewFromFloat(product.IntegralLogistics))
		// 计算成本价
		productCost = decimal.NewFromFloat(product.CostPrice).Mul(decimal.NewFromInt(int64(in.Qty))).Add(decimal.NewFromFloat(product.IntegralLogistics))
		// 计算积分
		productPoint = decimal.NewFromFloat(product.Integral).Mul(decimal.NewFromInt(int64(in.Qty)))

		// 商品限购校验
		//if product.Type == consts.ProductTypeGroup && // 团购商品
		if product.RestrictionType != 0 { // 限购类型不为0
			pass := false
			count := 0
			switch product.RestrictionType {
			case consts.ProductRestrictionTypeTimeCycle: // 根据时间周期限购
				pass, count, err = this.CycleBuyCheck(ctx, *product)
			case consts.ProductRestrictionTypeUserId: // 根据用户限购
				pass, count, err = this.UserBuyCheck(ctx, userInfo.Id, *product)
			}
			if err != nil {
				return nil, gerror.Wrap(err, "商品限购校验失败")
			}
			if !pass || gconv.Int(in.Qty) > (product.QuantityLimit-count) {
				if product.QuantityLimit-count <= 0 {
					return nil, gerror.New("您已达到商品限购数量\n无法购买！")
				} else {
					return nil, gerror.New(fmt.Sprintf("您已达到商品限购数量\n您还可以购买 %d 件该商品", product.QuantityLimit-count))
				}
			}
		}

		// 如果是会员，积分为0
		if userInfo.MemberStatus == consts.AdminMemberMemberStatusMember && // 会员
			product.Type == consts.ProductTypePoint && // 积分权益
			productPoint.GreaterThan(decimal.NewFromFloat(0)) && // 积分大于0
			in.PointType { // 会员购买
			// 会员限购检查
			pass, _, _, _ := this.CheckLimit(ctx, product.Id, userInfo.Id)
			if !pass {
				return nil, gerror.New("您已达到商品限购数量\n无法购买！")
			}
			productPoint = decimal.NewFromFloat(0)
		}

		// 积分余额检查
		if decimal.NewFromFloat(userInfo.Integral).LessThan(productPoint) {
			return nil, gerror.New("积分不足")
		}

		// 支付类型
		payMethod := consts.PayTypeWxPay
		switch product.Type {
		case consts.ProductTypePoint: // 积分权益
			payMethod = consts.PayTypePoint
			break
		case consts.ProductTypeEcommerce: // 积分电商
			payMethod = consts.PayTypePoint
			break
		case consts.ProductTypeGroup: // 团购订单
			payMethod = consts.PayTypeWxPay
			break
		}

		// 创建商品订单
		orderInput := sysin.UserOrderEditInp{
			Order: entity.Order{
				TraceId: "",
				UserId:  userInfo.Id,
				//StoreId:            in.StoreID,
				OrderType:          consts.GetOrderTypeByProductScene(product.Type),
				ProductId:          in.ProductID,
				ProductNewId:       in.ProductNewID,
				Qty:                in.Qty,
				PayMethod:          payMethod,
				UsePoints:          productPoint.InexactFloat64(),
				UseAmount:          productAmount.InexactFloat64(),
				CostPrice:          productCost.InexactFloat64(),
				Status:             consts.UserOrderStatusNot,
				Recipient:          in.Recipient,
				ShippingProvinceId: in.ShippingProvinceID,
				ShippingAddress:    in.ShippingAddress,
				Tel:                in.Tel,
				AuctionLogId:       in.AuctionLogId,
				ShareMemberId:      in.ShareMemberId,
				VipProportion:      product.VipProportion,
			},
		}
		orderID, err := this.Edit(ctx, &orderInput)
		if err != nil {
			glog.Errorf(ctx, "Failed to create order: %s", err.Error())
			return nil, err
		}

		productOrder, err = service.SysUserOrder().View(ctx, &sysin.UserOrderViewInp{
			Id: orderID,
		})
		if err != nil {
			glog.Errorf(ctx, "Failed to retrieve order: %v", err)
			return nil, err
		}
	}

	// 会员
	if in.MemberCardID != 0 {
		memberCard := &entity.MemberCard{}
		err = dao.MemberCard.Ctx(ctx).Where("id", in.MemberCardID).Scan(memberCard)
		if err != nil {
			return nil, err
		}
		memberAmount = memberAmount.Add(decimal.NewFromFloat(memberCard.Price))
		if subject != "" {
			subject = subject + "，"
		}

		// 判断是否重复购买
		if (memberCard.Type == consts.AdminMemberIdentityXiaoke && userInfo.RoleId >= consts.RoleXiaoke) ||
			(memberCard.Type == consts.AdminMemberIdentityService && userInfo.RoleId >= consts.RoleService) {
			return nil, gerror.Newf("您已是%s，无需购买", consts.GetRoleName(userInfo.RoleId))
		}

		// 设置
		var (
			address   = ""
			recipient = ""
			tel       = ""
			raData    = &sysin.ReceiverAddressViewModel{}
		)
		if memberCard.Type == consts.AdminMemberIdentityXiaoke || memberCard.Type == consts.AdminMemberIdentityService {
			// 修改用户信息
			err = service.AdminMember().UpdateInfo(ctx, &adminin.MemberUpdateInfoInp{
				ID:       contexts.GetUserId(ctx),
				RealName: in.RealName,
				IdCard:   in.IdCard,
			})
			if err != nil {
				return nil, gerror.Wrap(err, "修改用户信息失败")
			}

			if in.ReceiverAddressID > 0 {
				// 获取收货地址信息
				raData, err = service.SysReceiverAddress().View(ctx, &sysin.ReceiverAddressViewInp{
					Id: in.ReceiverAddressID,
				})
				if err != nil {
					return nil, err
				}
				if raData == nil || raData.MemberId != userInfo.Id {
					return nil, gerror.Newf("收货地址信息有误")
				}
				// 设置收货信息
				address = raData.ProvinceName + raData.CityName + raData.CountyName + raData.StreetName + raData.DetailInfo
				recipient = raData.UserName
				tel = raData.TelNumber
			}
		}

		// 订单标题
		subject = subject + "下楼休闲吧-" + memberCard.Name

		// 创建会员订单
		orderInput := sysin.UserOrderEditInp{
			Order: entity.Order{
				TraceId:            "",
				UserId:             userInfo.Id,
				OrderType:          consts.GetOrderTypeByProductScene(4),
				MemberCardId:       in.MemberCardID,
				ProductId:          in.JoinProductID, // 关联的商品ID
				Qty:                1,
				PayMethod:          consts.PayTypeWxPay,
				UsePoints:          0,
				UseAmount:          memberAmount.InexactFloat64(),
				Status:             consts.UserOrderStatusNot,
				Recipient:          recipient,
				Tel:                tel,
				ShippingAddress:    address,
				ShippingProvinceId: gconv.Int64(raData.PostalCode),
				ReceiverAddressId:  in.ReceiverAddressID,
				RealName:           in.RealName,
				IdCard:             in.IdCard,
			},
		}

		orderID, err2 := this.Edit(ctx, &orderInput)
		if err2 != nil {
			glog.Errorf(ctx, "Failed to create order: %s", err2.Error())
			return nil, err2
		}

		memberOrder, err2 = service.SysUserOrder().View(ctx, &sysin.UserOrderViewInp{
			Id: orderID,
		})
		if err2 != nil {
			glog.Errorf(ctx, "Failed to retrieve order: %v", err2)
			return nil, err2
		}

		// 创建物流信息
		if (memberCard.Type == consts.AdminMemberIdentityXiaoke || memberCard.Type == consts.AdminMemberIdentityService) && in.ReceiverAddressID > 0 {
			expressInfoId, err3 := service.ExpressinfoExpressInfo().Edit(ctx, &expressinfoin.ExpressInfoEditInp{
				ExpressInfo: entity.ExpressInfo{
					OrderUid:             memberOrder.Uid,
					MemberCardId:         gconv.Int(in.MemberCardID),
					UserId:               userInfo.Id,
					Recipient:            recipient,
					ShippingProvinceId:   gconv.Int64(raData.PostalCode),
					ShippingProvinceName: raData.ProvinceName + raData.CityName + raData.CountyName + raData.StreetName,
					ShippingAddress:      raData.DetailInfo,
					Tel:                  raData.TelNumber,
					Status:               consts.ExpressStatusNot,
				},
			})
			if err3 != nil {
				glog.Errorf(ctx, "创建物流信息失败: %s", err3.Error())
				return nil, err3
			}
			_, err = this.Edit(ctx, &sysin.UserOrderEditInp{
				Order: entity.Order{
					Id:            orderID,
					ExpressInfoId: expressInfoId,
				},
			})
			if err != nil {
				glog.Errorf(ctx, "更新订单物流信息失败: %s", err.Error())
				return nil, err
			}
		}
	}

	res = new(sysin.OrderPayModel)

	// 创建支付请求
	if productAmount.GreaterThan(decimal.NewFromFloat(0)) || memberAmount.GreaterThan(decimal.NewFromFloat(0)) {
		var createModel *payin.PayCreateModel
		createModel, err = service.Pay().Create(ctx, payin.PayCreateInp{
			Subject:    subject,
			Detail:     nil,
			OrderSn:    productOrder.Uid, // 商品订单号
			OrderMvSn:  memberOrder.Uid,  // 会员订单号
			OrderGroup: consts.OrderGroupDefault,
			Openid:     userInfo.OpenId,
			PayType:    consts.PayTypeWxPay,
			TradeType:  consts.TradeTypeWxMP,
			PayAmount:  productAmount.Add(memberAmount).InexactFloat64(), // 商品金额 + 会员金额
			ReturnUrl:  "",
		})
		if err != nil {
			glog.Errorf(ctx, "Failed to create payment: %v", err)
			return nil, err
		}
		res.AppId = createModel.Order.JsApi.Params.AppId
		res.NonceStr = createModel.Order.JsApi.Params.NonceStr
		res.Package = createModel.Order.JsApi.Params.Package
		res.PaySign = createModel.Order.JsApi.Params.PaySign
		res.SignType = createModel.Order.JsApi.Params.SignType
		res.TimeStamp = createModel.Order.JsApi.Params.TimeStamp
		// 商品订单添加支付信息
		if _, err = this.Model(ctx).WherePri(productOrder.Id).Data(g.Map{
			dao.Order.Columns().PayInfo: res,
		}).Update(); err != nil {
			return
		}
		// 会员订单添加支付信息
		if memberOrder.Id != 0 {
			if _, err = this.Model(ctx).WherePri(memberOrder.Id).Data(g.Map{
				dao.Order.Columns().PayInfo: res,
			}).Update(); err != nil {
				return
			}
		}
	}

	// 扣除积分
	if productPoint.GreaterThan(decimal.NewFromFloat(0)) {
		if _, err = service.AdminCreditsLog().SaveIntegral(ctx, &adminin.CreditsLogSaveIntegralInp{
			MemberId:    userInfo.Id,
			OrderID:     productOrder.Id,
			AppId:       contexts.GetModule(ctx),
			CreditGroup: consts.CreditGroupDecr,
			Num:         productPoint.InexactFloat64() * -1,
			Remark:      fmt.Sprintf("兑换权益: %s", subject),
		}); err != nil {
			return nil, gerror.New(err.Error())
		}
	}

	// 不需要支付钱
	if productAmount.Equal(decimal.NewFromInt(0)) && memberAmount.Equal(decimal.NewFromInt(0)) {
		// 订单改到积分支付

		hfsm.OFSM.PushState(productOrder.Id, consts.NotToPayEvent)
	}
	return
}

// RePay 重新支付
func (this *sSysUserOrder) RePay(ctx context.Context, in *sysin.UnPayOrderRePayInp) (res *sysin.OrderPayModel, err error) {
	res = new(sysin.OrderPayModel)
	var order *entity.Order
	if err = this.Model(ctx).Fields(
		dao.Order.Columns().UserId,
		dao.Order.Columns().Id,
		dao.Order.Columns().PayInfo,
		dao.Order.Columns().Status,
		dao.Order.Columns().UsePoints,
		dao.Order.Columns().ProductId,
	).Where(dao.Order.Columns().Uid, in.OrderUID).Scan(&order); err != nil {
		return
	}
	if order == nil {
		err = gerror.New("订单不存在")
		return
	}
	if order.Status != consts.UserOrderStatusNot {
		err = gerror.New("订单已处理，请勿重复操作")
		return
	}

	productPoint := decimal.NewFromFloat(order.UsePoints)
	if productPoint.GreaterThan(decimal.NewFromFloat(0)) {
		// 获取商品信息
		product, err := service.SysProduct().View(ctx, &sysin.ProductViewInp{
			Id: order.ProductId,
		})
		if err != nil {
			glog.Errorf(ctx, "Failed to retrieve product: %v", err)
			return nil, err
		}

		// 扣除积分
		if productPoint.GreaterThan(decimal.NewFromFloat(0)) {
			if _, err = service.AdminCreditsLog().SaveIntegral(ctx, &adminin.CreditsLogSaveIntegralInp{
				MemberId:    order.UserId,
				OrderID:     order.Id,
				AppId:       contexts.GetModule(ctx),
				CreditGroup: consts.CreditGroupDecr,
				Num:         productPoint.InexactFloat64() * -1,
				Remark:      fmt.Sprintf("兑换权益: %s", product.Name),
			}); err != nil {
				return nil, gerror.New(err.Error())
			}
		}

		// 订单改到积分支付
		hfsm.OFSM.PushState(order.Id, consts.NotToPayEvent)
	}

	if !order.PayInfo.IsNil() {
		if err = json.Unmarshal(order.PayInfo.MustToJson(), &res); err != nil {
			return nil, err
		}
	}
	return
}

// RefundRequest 退款请求
func (this *sSysUserOrder) RefundRequest(ctx context.Context, in *sysin.RefundRequestInp) (res *sysin.RefundRequestModel, err error) {
	tx, err := g.DB().Begin(ctx)
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	var order *entity.Order
	err = service.SysUserOrder().Model(ctx).Where(dao.Order.Columns().Uid, in.OrderUID).Scan(&order)
	if err != nil {
		return
	}
	if !lo.Contains([]string{consts.UserOrderStatusWaitExpress, consts.UserOrderStatusWaitVerify}, order.Status) {
		err = gerror.New("订单状态不允许直接退款，请与客服联系")
		return
	}

	if lo.Contains([]string{consts.UserOrderStatusWaitExpress, consts.UserOrderStatusWaitVerify}, order.Status) {
		switch order.OrderType {
		case consts.OrderTypePointRight, consts.OrderTypeGroupOrder:
			hfsm.OFSM.PushState(order.Id, consts.WaitVerifyToReturnRequestEvent, ctx)
		case consts.OrderTypePointECommerce:
			hfsm.OFSM.PushState(order.Id, consts.WaitExpressToReturnRequestEvent, ctx)
		}
		if _, err = this.Model(ctx).WherePri(order.Id).Data(g.Map{
			dao.Order.Columns().RefundReason: in.Reason,
		}).Update(); err != nil {
			return
		}
		// 直接退款
		hfsm.OFSM.PushState(order.Id, consts.ReturnRequestToReturningEvent, ctx)

	}
	var refund entity.PayRefund
	if err = service.PayRefund().Model(ctx).Where(dao.PayRefund.Columns().OrderSn, order.Uid).Scan(&refund); err != nil {
		return
	}
	res = new(sysin.RefundRequestModel)
	res.PayRefund = refund
	return
}

func (this *sSysUserOrder) AuctionOrderCreate(ctx context.Context, in *sysin.AuctionOrderPayInp) (err error) {
	var (
		product *sysin.ProductViewModel
		orderID int64
	)
	product, err = service.SysProduct().View(ctx, &sysin.ProductViewInp{
		Id: in.ProductID,
	})
	if err != nil {
		glog.Errorf(ctx, "Failed to retrieve product: %v", err)
		return
	}
	// 创建订单
	orderInput := sysin.UserOrderEditInp{
		Order: entity.Order{
			TraceId: "",
			UserId:  in.UserID,
			//StoreId:            in.StoreID,
			OrderType:    consts.GetOrderTypeByProductScene(product.Type),
			ProductId:    in.ProductID,
			ProductNewId: 0,
			Qty:          1,
			PayMethod:    consts.PayTypePoint,
			UsePoints:    in.Point.InexactFloat64(),
			UseAmount:    in.Amount.InexactFloat64(),
			Status:       consts.UserOrderStatusNot,
			//Recipient:          in.Recipient,
			//ShippingProvinceId: in.ShippingProvinceID,
			//ShippingAddress:    in.ShippingAddress,
			//Tel:                in.Tel,
			AuctionLogId: in.AuctionLogID,
		},
	}
	orderID, err = this.Edit(ctx, &orderInput)
	if err != nil {
		glog.Errorf(ctx, "Failed to create order: %s", err.Error())
		return
	}

	order, err := service.SysUserOrder().View(ctx, &sysin.UserOrderViewInp{
		Id: orderID,
	})
	if err != nil {
		glog.Errorf(ctx, "Failed to retrieve order: %v", err)
		return err
	}

	userInfo, err := service.AdminMember().View(ctx, &adminin.MemberViewInp{
		Id: in.UserID,
	})
	if err != nil {
		glog.Errorf(ctx, "Failed to retrieve user: %v", err)
		return
	}

	res := new(sysin.OrderPayModel)

	// 创建支付请求
	if in.Amount.GreaterThan(decimal.NewFromFloat(0)) {
		var createModel *payin.PayCreateModel
		createModel, err = service.Pay().Create(ctx, payin.PayCreateInp{
			Subject:    product.Name,
			Detail:     nil,
			OrderSn:    order.Uid,
			OrderGroup: consts.OrderGroupDefault,
			Openid:     userInfo.OpenId,
			PayType:    consts.PayTypeWxPay,
			TradeType:  consts.TradeTypeWxMP,
			PayAmount:  in.Amount.InexactFloat64(),
			ReturnUrl:  "",
		})
		if err != nil {
			glog.Errorf(ctx, "Failed to create payment: %v", err)
			return err
		}
		res.AppId = createModel.Order.JsApi.Params.AppId
		res.NonceStr = createModel.Order.JsApi.Params.NonceStr
		res.Package = createModel.Order.JsApi.Params.Package
		res.PaySign = createModel.Order.JsApi.Params.PaySign
		res.SignType = createModel.Order.JsApi.Params.SignType
		res.TimeStamp = createModel.Order.JsApi.Params.TimeStamp
		if _, err = this.Model(ctx).WherePri(orderID).Data(g.Map{
			dao.Order.Columns().PayInfo: res,
		}).Update(); err != nil {
			return
		}
		return
	}

	// 扣除积分
	if in.Point.GreaterThan(decimal.NewFromFloat(0)) {
		if _, err = service.AdminCreditsLog().SaveIntegral(ctx, &adminin.CreditsLogSaveIntegralInp{
			MemberId:    in.UserID,
			OrderID:     orderID,
			AppId:       contexts.GetModule(ctx),
			CreditGroup: consts.CreditGroupDecr,
			Num:         in.Point.InexactFloat64() * -1,
			Remark:      fmt.Sprintf("兑换权益: %s", product.Name),
		}); err != nil {
			return gerror.New(err.Error())
		}
	}

	// 不需要支付钱
	if in.Amount.Equal(decimal.NewFromInt(0)) {
		hfsm.OFSM.PushState(orderID, consts.NotToPayEvent)
	}
	return
}

// 会员限购检查
func (this *sSysUserOrder) CheckLimit(ctx context.Context, productId, memberId int64) (pass bool, total, limit int, err error) {
	user, err := service.AdminMember().GetById(ctx, &adminin.GetByIdInp{
		Id: memberId,
	})
	if err != nil {
		return false, 0, 0, err
	}
	total, err = service.SysUserOrder().Model(ctx).WhereIn(dao.Order.Columns().Status, consts.UserOrderStatusPayStatus).
		Where(dao.Order.Columns().ProductId, productId).
		Where(dao.Order.Columns().UserId, contexts.GetUserId(ctx)).
		Where(dao.Order.Columns().UsePoints, 0).
		WhereBetween(dao.Order.Columns().CreatedAt, user.MemberStartTime.Format("Y-m-d H:i:s"), user.ExpireTime.Format("Y-m-d H:i:s")).
		Count()
	if err != nil {
		return false, 0, 0, err
	}
	if total >= user.ExchangeCount {
		return false, total, user.ExchangeCount, nil
	}
	return true, total, user.ExchangeCount, nil
}

// 时间周期检查
func (this *sSysUserOrder) CycleBuyCheck(ctx context.Context, product sysin.ProductViewModel) (pass bool, total int, err error) {
	now := gtime.Now()
	var minTime *gtime.Time
	switch product.Cycle {
	case 1: // 日
		minTime = now.AddDate(0, 0, -1)
	case 2: // 周
		minTime = now.AddDate(0, 0, -7)
	case 3: // 月
		minTime = now.AddDate(0, -1, 0)
	case 4: // 年
		minTime = now.AddDate(-1, 0, 0)
	default:
		err = gerror.New("Invalid cycle")
		return false, 0, err
	}
	// 输出格式化后的时间
	sum, err := service.SysUserOrder().Model(ctx).WhereIn(dao.Order.Columns().Status, consts.UserOrderStatusPayStatus).
		Where(dao.Order.Columns().ProductId, product.Id).
		Where(dao.Order.Columns().UserId, contexts.GetUserId(ctx)).
		WhereBetween(dao.Order.Columns().CreatedAt, minTime.Format("Y-m-d H:i:s"), now.Format("Y-m-d H:i:s")).
		Sum(dao.Order.Columns().Qty)
	if err != nil {
		return false, 0, err
	}
	total = gconv.Int(sum)
	if total >= product.QuantityLimit {
		return false, total, nil
	}
	return true, total, nil
}

// 用户限购检查
func (this *sSysUserOrder) UserBuyCheck(ctx context.Context, userID int64, product sysin.ProductViewModel) (pass bool, total int, err error) {
	sum, err := service.SysUserOrder().Model(ctx).
		WhereIn(dao.Order.Columns().Status, consts.UserOrderStatusPayStatus).
		Where(dao.Order.Columns().UserId, userID).
		Where(dao.Order.Columns().ProductId, product.Id).
		Sum(dao.Order.Columns().Qty)
	if err != nil {
		return false, 0, err
	}
	total = gconv.Int(sum)
	if total >= product.QuantityLimit {
		return false, total, nil
	}
	return true, total, nil
}

// 查询个人订单总数
func (this *sSysUserOrder) Count(ctx context.Context, id int64) (res int, err error) {
	// 获取用户订单总数
	res, err = service.SysUserOrder().Model(ctx).
		Where(dao.Order.Columns().UserId, id).
		WhereNot(dao.Order.Columns().Deleted, 1).
		Count()
	if err != nil {
		return
	}
	return
}

// 查询个人新人商品订单总数
func (this *sSysUserOrder) ProductNewCount(ctx context.Context, id int64) (res int, err error) {
	// 获取用户订单总数
	res, err = service.SysUserOrder().Model(ctx).
		Where(dao.Order.Columns().UserId, id).
		WhereNot(dao.Order.Columns().ProductNewId, 0).
		Where(dao.Order.Columns().OrderType, consts.OrderTypePointRight).
		Count()
	if err != nil {
		return
	}
	return
}

// 查询个人已支付的订单总数
func (this *sSysUserOrder) CountPay(ctx context.Context, id int64) (res int, err error) {
	// 获取用户订单总数
	res, err = service.SysUserOrder().Model(ctx).
		Where(dao.Order.Columns().UserId, id).
		WhereIn(dao.Order.Columns().Status, consts.UserOrderStatusPayStatus).
		Count()
	return
}

// 用户轮播动态信息
func (this *sSysUserOrder) CarouselDynamic(ctx context.Context) (list []*apiin.CarouselDynamicModel, err error) {
	err = dao.Order.Ctx(ctx).Fields(
		fmt.Sprintf("CONCAT(SUBSTRING(%s, 1, 1), '***', SUBSTRING(%s, CHAR_LENGTH(%s), 1)) AS name", dao.Product.Table()+".name", dao.Product.Table()+".name", dao.Product.Table()+".name"),
		fmt.Sprintf("CONCAT(SUBSTRING(%s, 1, 1), '***', SUBSTRING(%s, CHAR_LENGTH(%s), 1)) AS nickname", dao.AdminMember.Table()+".nickname", dao.AdminMember.Table()+".nickname", dao.AdminMember.Table()+".nickname"),
		dao.AdminMember.Table()+".avatar",
	).
		LeftJoin(dao.Product.Table(), dao.Order.Table()+".product_id="+dao.Product.Table()+".id").
		LeftJoin(dao.AdminMember.Table(), dao.Order.Table()+".user_id="+dao.AdminMember.Table()+".id").
		WhereIn(dao.Order.Table()+".order_type", []string{
			consts.OrderTypeGroupOrder,
			consts.OrderTypeMemberOrder,
		}).
		Where(dao.AdminMember.Table() + ".nickname != ''").
		Where(dao.AdminMember.Table() + ".avatar != ''").
		//Where(dao.Product.Table() + ".name != ''").
		Order(dao.Order.Table() + ".created_at desc").
		Limit(20).
		Scan(&list)
	if err != nil {
		return nil, err
	}
	return list, nil
}
